package io.xxx.omni.osc.sync

import com.kuaishou.merchant.open.api.KsMerchantRequest
import com.kuaishou.merchant.open.api.KsMerchantResponse
import com.kuaishou.merchant.open.api.client.AccessTokenKsMerchantClient
import com.kuaishou.merchant.open.api.request.KsMerchantOrderListRequest
import com.kuaishou.merchant.open.api.request.KsMerchantRefundListRequest
import com.kuaishou.merchant.open.api.response.KsMerchantOrderListResponse
import com.kuaishou.merchant.open.api.response.KsMerchantRefundListResponse
import io.xxx.omni.osc.common.toLocalDateTime
import io.xxx.omni.osc.common.zoneOffset
import io.xxx.omni.osc.domain.Document
import io.xxx.omni.osc.domain.DocumentType
import io.xxx.omni.osc.domain.PlatformIdentity
import io.xxx.omni.osc.domain.Store
import org.springframework.stereotype.Component
import java.time.LocalDateTime

/**
 * 快手
 */
// https://open.kwaixiaodian.com/docs/dev?pageSign=8cca5d25ba0015e5045a7ebec6383b741614263875756
abstract class KsPorter<T : KsMerchantRequest<R>, R : KsMerchantResponse>
    : CursorDocumentPorter<T, R>(), PlatformIdentity.KuaiShou {

    override fun getResponse(context: JobContext, prevResponse: R?): R {
        val (store, startTime, endTime) = context
        val clientName = "${platform.id}Client${store.id}"
        val client = applicationContext.getBean(clientName, AccessTokenKsMerchantClient::class.java)
        val request = buildRequest(store, startTime, endTime, prevResponse)
        val response = client.execute(request)
        if (!response.isSuccess) {
            throwException(context, request, response)
        }
        return response
    }

    override fun hasNext(response: R): Boolean {
        val cursor = getCursor(response)
        return cursor != "nomore"
    }

    protected abstract fun getCursor(response: R?): String

    protected abstract fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        prevResponse: R?,
    ): T
}

// 订单
// https://open.kwaixiaodian.com/docs/api?apiName=open.seller.order.pcursor.list&categoryId=43&version=1
@Component
class KsTradePorter : KsPorter<KsMerchantOrderListRequest, KsMerchantOrderListResponse>() {

    override fun buildDocuments(context: JobContext, response: KsMerchantOrderListResponse): List<Document> {
        return response
            .merchantOrderListData
            .orderInfoList
            .map {
                val sn = it.oid.toString()
                val status = it.status.toString()
                val modified = it.updateTime.toLocalDateTime()
                Document(sn, status, modified, it)
            }
    }

    override fun getCursor(response: KsMerchantOrderListResponse?) =
        response?.merchantOrderListData?.pcursor ?: ""

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        prevResponse: KsMerchantOrderListResponse?
    ): KsMerchantOrderListRequest {
        val request = KsMerchantOrderListRequest()
        request.accessToken = store.authorization["signSecret"]
        request.apiMethodVersion = 1
        request.pageSize = pageSize
        request.type = 1
        request.sort = 1
        request.queryType = 2
        request.beginTime = startTime.toInstant(zoneOffset).toEpochMilli()
        request.endTime = endTime.toInstant(zoneOffset).toEpochMilli()
        request.cpsType = 0
        request.pcursor = getCursor(prevResponse)
        return request
    }
}

// 退单
// https://open.kwaixiaodian.com/docs/api?apiName=open.seller.order.refund.pcursor.list&categoryId=42&version=1
@Component
class KsRefundPorter : KsPorter<KsMerchantRefundListRequest, KsMerchantRefundListResponse>() {

    override val documentType = DocumentType.REFUND

    override fun buildDocuments(context: JobContext, response: KsMerchantRefundListResponse): List<Document> {
        return response
            .merchantRefundListData
            .refundOrderInfoList
            .map {
                val sn = it.refundId.toString()
                val rsn = it.oid.toString()
                val status = it.status.toString()
                val modified = it.updateTime.toLocalDateTime()
                Document(sn, rsn, status, modified, it)
            }
    }

    override fun getCursor(response: KsMerchantRefundListResponse?) = response?.merchantRefundListData?.pcursor ?: ""

    override fun buildRequest(
        store: Store,
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        prevResponse: KsMerchantRefundListResponse?
    ): KsMerchantRefundListRequest {
        val request = KsMerchantRefundListRequest()
        request.accessToken = store.authorization["accessToken"]
        request.apiMethodVersion = 1

        request.beginTime = startTime.toInstant(zoneOffset).toEpochMilli()
        request.endTime = endTime.toInstant(zoneOffset).toEpochMilli()
        request.type = 9
        request.pageSize = pageSize
        request.sort = 1
        request.queryType = 2
        request.negotiateStatus = 1
        request.pcursor = getCursor(prevResponse)
        return request
    }
}